<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>

    // 1.JSON转换
    // 缺点：  
    // （1）如果对象里有函数,函数无法被拷贝下来 
    // （2）无法拷贝copyObj对象原型链上的属性和方法 
    // （3）当数据的层次很深，会栈溢出 
    var json_obj1 = { aa: 11, bb: [{ dd: 44 }, [{ ff: 55 }]] }
    var json_obj2 = JSON.parse(JSON.stringify(json_obj1))
    console.log('JSON转换', json_obj2);

    // 2.普通递归函数
    // 缺点： 
    // （1）无法保持引用 
    // （2）当数据的层次很深，会栈溢出
    function deepCopy(source) {
      if (typeof source !== 'object' || source === null) return source; //如果不是对象的话直接返回
      let target = Array.isArray(source) ? [] : {} //数组兼容
      for (var k in source) {
        if (source.hasOwnProperty(k)) {
          if (typeof source[k] === 'object') {
            target[k] = deepCopy(source[k])
          } else {
            target[k] = source[k]
          }
        }
      }
      return target
    }

    // 3.防栈溢出函数
    // 优点： 
    // （1）不会栈溢出 
    // （2）支持很多层级的数据

    function cloneLoop(x) {
      if (typeof x !== 'object' || x === null) return x
      const root = Array.isArray(x) ? [] : {};
      // 栈
      const loopList = [{ parent: root, key: undefined, data: x, }];
      while (loopList.length) {
        // 深度优先
        const node = loopList.pop();
        const parent = node.parent;
        const key = node.key;
        const data = node.data;

        // 初始化赋值目标，key为undefined则拷贝到父元素，否则拷贝到子元素
        let res = parent;
        if (typeof key !== 'undefined') {
          res = parent[key] = Array.isArray(data) ? [] : {};
        }

        for (let k in data) {
          if (data.hasOwnProperty(k)) {
            if (typeof data[k] === 'object') {
              // 下一次循环
              loopList.push({
                parent: res,
                key: k,
                data: data[k],
              });
            } else {
              Array.isArray(data) ? res.push(data[k]) : res[k] = data[k];
            }
          }
        }
      }
      return root;
    }

    // var obj = 123
    // var obj = {
    //   aa: 11, bb: 22, fn: function () {
    //     console.log(88);
    //   }
    // }
    // var obj = ['aaa', 'bbb']

    // var obj = [{ aa: 11, bb: 22 }, { cc: 33 }]
    var obj = { aa: 11, bb: [{ dd: 44 }, [{ ff: 55 }]] }

    var clone = cloneLoop(obj)
    console.log(clone);
    // obj[0].bb = 77
    // console.log('clone', clone);
    console.log('obj', obj);

    // console.log(JSON.parse(JSON.stringify(obj)));
  </script>
</body>

</html>